<script setup>
import { reactive, onMounted } from 'vue'
import MarkdownIt from 'markdown-it'
import mdKatex from '@traptitech/markdown-it-katex'
import hljs from 'highlight.js'
import Clipboard from 'clipboard'

const mdi = new MarkdownIt({
  linkify: true,
  highlight(code, language) {
    // 检查language是否存在，并获取language
    const validLang = !!(language && hljs.getLanguage(language))
    // 如果language存在
    if (validLang) {
      const lang = language ?? ''
      return highlightBlock(hljs.highlight(code, { language: lang }).value, lang)
    }
    // 否则，使用自动检测
    return highlightBlock(hljs.highlightAuto(code).value, '')
  }
})
mdi.use(mdKatex, { blockClass: 'katexmath-block rounded-md p-[10px]', errorColor: ' #cc0000' })

/**
 * 高亮显示代码块。
 * @param {string} str 需要高亮的代码字符串。
 * @param {string} lang 代码的语言。
 * @returns {string} 返回包含高亮代码的 HTML 字符串。
 */
function highlightBlock(str, lang) {
  // pre-code-header类元素就是显示当前高亮的代码语言和复制按钮区域，这块的样式需要自己定义
  // data-clipboard-target 属性用于指定复制按钮点击后需要复制的文本区域
  return `<pre class="pre-code-box"><div class="pre-code-header"><span class="language">${lang}</span><span id='copy-btn' class="copy" data-clipboard-target=".code-block-body">复制代码</span></div><div class="pre-code" ><code class="hljs code-block-body ${lang}">${str}</code></div></pre>`
}
/**
 * 将 Markdown 文本转换为 HTML。
 * @param {string} value Markdown 文本。
 * @returns {string} 转换后的 HTML 文本。
 */
const getMdiText = (value) => {
  return mdi.render(value)
}

const state = reactive({
  htmlStr: ''
})

onMounted(() => {
  // 将 Markdown 文本转换为包含 HTML 样式的文本
  state.htmlStr = getMdiText(
    "Server-Sent Events（SSE）是一种网络技术，允许服务器向客户端推送信息，而不需要客户端显式地请求。SSE 提供了一个从服务器到客户端的单向、持久连接，使得服务器可以随时将数据发送到客户端。这与传统的 HTTP 请求/响应模式不同，后者要求客户端发起请求后才能接收到服务器的响应。\n\nSSE 的主要特点包括：\n\n1. **单次连接**：客户端只需与服务器建立一个连接，服务器就可以持续发送数据。\n2. **基于文本**：服务器发送的数据通常是文本格式，可以是纯文本或者 JSON。\n3. **自动重连**：如果连接断开，客户端通常会尝试自动重新连接。\n4. **事件驱动**：服务器可以发送不同类型的事件，客户端可以监听这些事件。\n5. **轻量级**：SSE 使用 HTTP 协议，不需要额外的协议或框架。\n\nSSE 在浏览器中的支持是通过 `EventSource` API 实现的。以下是一个简单的 SSE 客户端示例：\n\n```javascript\n// 创建一个新的 EventSource 连接\nvar eventSource = new EventSource('/path/to/stream');\n\n// 监听消息事件\neventSource.onmessage = function(event) {\n  console.log('收到消息:', event.data);\n};\n\n// 监听自定义事件\neventSource.addEventListener('myevent', function(event) {\n  console.log('自定义事件:', event.data);\n});\n\n// 监听打开事件\neventSource.onopen = function(event) {\n  console.log('连接已打开:', event);\n};\n\n// 监听错误事件\neventSource.onerror = function(event) {\n  console.log('发生错误:', event);\n  eventSource.close(); // 发生错误时可以选择关闭连接\n};\n```\n\n在服务器端，SSE 需要通过发送特定格式的 HTTP 响应来实现。服务器响应的 MIME 类型通常是 `text/event-stream`，并且响应内容包含一系列以 `data:` 开头的事件，每个事件后跟一个换行符。服务器可以随时发送新的事件，客户端会实时接收到这些事件。\n\nSSE 适用于需要服务器向客户端推送实时更新场景，例如股票行情、实时聊天、通知推送等。它是构建实时 web 应用的一种简单而有效的方式。"
  )

  // 复制内容库
  const clipboard = new Clipboard('#copy-btn')
  clipboard.on('success', (e) => {
    console.info('Action:', e.action)
    console.info('Text:', e.text)
    console.info('Trigger:', e.trigger)
    alert('复制成功')
    e.clearSelection()
    // 释放内存
    clipboard.destroy()
  })
  clipboard.on('error', (e) => {
    console.error('Action:', e.action)
    console.error('Trigger:', e.trigger)
    alert('复制失败')
    // 释放内存
    clipboard.destroy()
  })
})
</script>

<template>
  <div v-html="state.htmlStr"></div>
</template>
<style>
.pre-code-header {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  height: 36px !important;
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: flex;
  width: 100%;
  padding: 6px 12px;
  -webkit-box-pack: justify;
  -webkit-justify-content: space-between;
  -moz-box-pack: justify;
  justify-content: space-between;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -moz-box-align: center;
  align-items: center;
  -webkit-border-radius: 8px 8px 0 0;
  -moz-border-radius: 8px 8px 0 0;
  border-radius: 8px 8px 0 0;
  background: #e6e9f2 !important;
}
.language {
  color: var(--b-1, #1a2029);
  font-family: PingFang SC;
  font-size: 12px;
  font-style: normal;
  font-weight: 600;
  line-height: 20px;
}
.copy {
  position: absolute;
  right: 10px;
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: flex;
  padding: 2px 8px;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -moz-box-pack: center;
  justify-content: center;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -moz-box-align: center;
  align-items: center;
  gap: 2px;
  -webkit-border-radius: 6px;
  -moz-border-radius: 6px;
  border-radius: 6px;
  background: hsla(0, 0%, 100%, 0.6);
  color: var(--b-1, #1a2029);
  font-family: PingFang SC;
  font-size: 12px;
  font-style: normal;
  font-weight: 400;
  line-height: 20px;
}

.copy:hover {
  color: var(--blue, #2454ff);
  cursor: pointer;
}
</style>
